<script lang="ts" setup>
import { ref, defineProps, defineExpose, watch, onBeforeUpdate, toRef } from 'vue'
import { ElMessage, FormInstance } from 'element-plus'
import formItem from './form-item.vue'
interface Props {
  formValue: object // 表单form
  formList?: Array<any> // 表单项
  isReadonly?: boolean
  zdlxArr?: Array<any>
  formAttr?: {
    labelPosition?: string
    inline?: boolean
    labelWidth?: string
    size?: string
    requireAsteriskPosition?: string
    scrollToError?: boolean
    showMessage?: boolean
    inlineMessage?: boolean
    statusIcon?: boolean
    hideRequiredAsterisk?: boolean
  }
}
const props = withDefaults(defineProps<Props>(), {
  formAttr: () => {
    return {
      labelPosition: 'right',
      inline: true,
      size: '',
      requireAsteriskPosition: 'left',
      labelWidth: '140px',
      scrollToError: false,
      showMessage: false,
      inlineMessage: false,
      statusIcon: false,
      hideRequiredAsterisk: false,
    }
  },
  isReadonly: false,
})
// 生命周期
onBeforeUpdate(() => {
  refs.length = 0
})
// 生命周期
onBeforeUpdate(() => {
  refs.length = 0
})
watch(
  () => props.formValue,
  (val) => {
    comFormValue.value = val
  },
  {
    deep: true,
  },
)
const emit = defineEmits(['exportCallBack'])
/**
 * 数据回填
 */
const comFormValue = ref<any>(props.formValue)
// 修改值
const updateModelValue = (val: string, keyWord: string, el: any) => {
  const valKey = el[keyWord]
  comFormValue.value[valKey as keyof typeof comFormValue] = val
}
// 改变联动
const refs: any = []
const setRefs = (bm: string) => {
  const refValue = toRef(refs, bm)
  return (el: any) => {
    refValue.value = el
  }
}
/* 表单改变回调 */
const changeCallBack = (el: any, key: string) => {
  el[key].map((cur: { name: string; value: string[] }) => {
    // 清空指定项值
    if (cur.name === 'clearFormValue') {
      clearFormValue(cur.value)
    } else if (cur.name === 'getOption') {
      // 获取指定项数据源
      getOption(cur.value)
    } else if (cur.name === 'setOption') {
      setOption(cur.value)
    }
  })
}
/* 清空表单项值 */
const clearFormValue = (arr: string[]) => {
  arr.map((cur: string) => {
    if (refs[cur]) {
      refs[cur].clearData()
    } else {
      comFormValue.value[cur] = ''
    }
  })
}
/* 获取表单项数据源 */
const getOption = (arr: string[]) => {
  arr.map((cur) => {
    refs[cur].getOption()
  })
}
/* 设置数据源 */
const setOption = (arr: string[]) => {
  arr.map((cur: any) => {
    refs[cur.to].setOption(comFormValue.value[cur.from], cur.label, cur.value)
  })
}
/* 添加表格行 */
const addCol = (cur: string) => {
  refs[cur].addCol()
}
/*
 * 清空表单校验
 */
const setRules = () => {
  ruleForm.value?.resetFields()
}

/*
 * 调用保存，验证表单成功返回数据
 */
const ruleForm = ref<FormInstance>()
const validateForm = async () => {
  const flag = await ruleForm.value?.validate().catch(() => {
    ElMessage.warning('表单校验失败！')
  })
  if (flag) {
    // 验证通过，返回表单数据
    return comFormValue.value
  } else {
    return false
  }
}
// 定义事件
const exportCallBack = (type: string, funName: string, el: any) => {
  if (el[type]) {
    // 如果有事件回调
    changeCallBack(el, type)
  }
  // 因为可能存在打开抽屉的事件，所以还是需要抛出事件
  emit('exportCallBack', funName)
}

// 获取下拉、下拉树当前选中的options
const getNodeOption = (key: string) => {
  // key 表单项
  return refs[key]?.getNodeOption()
}
defineExpose({ validateForm, setRules, addCol, getOption, getNodeOption })
</script>
<template>
  <div class="dt-form">
    <el-form ref="ruleForm" :model="comFormValue" v-bind="props.formAttr">
      <el-form-item
        :label-width="el.name ? props.formAttr.labelWidth : '0'"
        v-for="el in formList"
        :key="el.value"
        :prop="el.value"
        :class="el.className"
        :label="el.name"
        :rules="el.rules"
        :style="{ width: el.width || '100%' }"
      >
        <form-item
          :form-item="el"
          :ref="setRefs(el.value)"
          v-model="comFormValue[el.value]"
          :is-readonly="isReadonly"
          :form="comFormValue"
          :zdlxArr="zdlxArr"
          @exportCallBack="exportCallBack"
          @updateModelValue="updateModelValue"
          @changeCallBack="changeCallBack"
        />
      </el-form-item>
    </el-form>
  </div>
</template>
<style lang="scss" scoped>
.ep-form--inline .ep-form-item {
  margin-right: 0;
}
</style>
